#ifndef __BLOCK_QUEUE__
#define __BLOCK_QUEUE__

#include <iostream>
#include <string>
#include <queue>
#include <unistd.h>
#include <pthread.h>

using namespace std;

template <class T>
class BlockQueue
{
    bool Isfull()
    {
        return _cap == _block_queue.empty();
    }
    bool IsEmpty()
    {
        return _block_queue.empty();
    }
public:
    BlockQueue(int cap)
    :_cap(cap)
    {
        _pro_waitnum = 0;
        _con_waitnum = 0;
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_pro_cond, nullptr);
        pthread_cond_init(&_con_cond, nullptr);
    }

    void Enqueue(T &in)
    {
        pthread_mutex_lock(&_mutex);
        while(Isfull())
        {
            _pro_waitnum++;
            pthread_cond_wait(&_pro_cond, &_mutex);
            _pro_waitnum--;
        }
        _block_queue.push(in);
        if(_con_waitnum > 0)
        {
            pthread_cond_signal(&_con_cond);
        }

        pthread_mutex_unlock(&_mutex);
    }
    void Outqueue(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())///while 防止消费者被伪唤醒
        {
            _con_waitnum++;
            pthread_cond_wait(&_con_cond, &_mutex);
            _con_waitnum--;
        }
        *out = _block_queue.front();
        _block_queue.pop();
        if(_pro_waitnum > 0)
        {
            pthread_cond_signal(&_pro_cond);
        }

        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pro_cond);
        pthread_cond_destroy(&_con_cond);
    }
private:
    int _cap;
    queue<T> _block_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _pro_cond;
    pthread_cond_t _con_cond;
    bool _isrunning;
    int _pro_waitnum;
    int _con_waitnum;
};

#endif